﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Text;

namespace CSRedis.NetCore
{
	/// <summary>
	/// A list of endpoints
	/// </summary>
	public sealed class EndPointCollection : Collection<EndPoint>
	{
		/// <summary>
		/// Create a new EndPointCollection
		/// </summary>
		public EndPointCollection() : base()
		{
		}

		/// <summary>
		/// Create a new EndPointCollection
		/// </summary>
		public EndPointCollection(IList<EndPoint> endpoints) : base(endpoints)
		{
		}

		/// <summary>
		/// Format an endpoint
		/// </summary>
		public static string ToString(EndPoint endpoint)
		{
			return Format.ToString(endpoint);
		}

		/// <summary>
		/// Attempt to parse a string into an EndPoint
		/// </summary>
		public static EndPoint TryParse(string endpoint)
		{
			return Format.TryParseEndPoint(endpoint);
		}
		/// <summary>
		/// Adds a new endpoint to the list
		/// </summary>
		public void Add(string hostAndPort)
		{
			var endpoint = Format.TryParseEndPoint(hostAndPort);
			if (endpoint == null) throw new ArgumentException();
			Add(endpoint);
		}

		/// <summary>
		/// Adds a new endpoint to the list
		/// </summary>
		public void Add(string host, int port)
		{
			Add(Format.ParseEndPoint(host, port));
		}

		/// <summary>
		/// Adds a new endpoint to the list
		/// </summary>
		public void Add(IPAddress host, int port)
		{
			Add(new IPEndPoint(host, port));
		}

		/// <summary>
		/// See Collection&lt;T&gt;.InsertItem()
		/// </summary>
		protected override void InsertItem(int index, EndPoint item)
		{
			if (item == null) throw new ArgumentNullException(nameof(item));
			if (Contains(item)) throw new ArgumentException("EndPoints must be unique", nameof(item));
			base.InsertItem(index, item);
		}
		/// <summary>
		/// See Collection&lt;T&gt;.SetItem()
		/// </summary>
		protected override void SetItem(int index, EndPoint item)
		{
			if (item == null) throw new ArgumentNullException(nameof(item));
			int existingIndex;
			try
			{
				existingIndex = IndexOf(item);
			}
			catch (NullReferenceException)
			{
				// mono has a nasty bug in DnsEndPoint.Equals; if they do bad things here: sorry, I can't help
				existingIndex = -1;
			}
			if (existingIndex >= 0 && existingIndex != index) throw new ArgumentException("EndPoints must be unique", nameof(item));
			base.SetItem(index, item);
		}

		internal void SetDefaultPorts(int defaultPort)
		{
			for (int i = 0; i < Count; i++)
			{
				var endpoint = this[i];
				var dns = endpoint as DnsEndPoint;
				if (dns?.Port == 0)
				{
					this[i] = new DnsEndPoint(dns.Host, defaultPort, dns.AddressFamily);
					continue;
				}
				var ip = endpoint as IPEndPoint;
				if (ip?.Port == 0)
				{
					this[i] = new IPEndPoint(ip.Address, defaultPort);
					continue;
				}
			}
		}
	}
}
